package com.joy.openggl.graphics.mesh;

import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.graphics.Bitmap;
import android.opengl.GLUtils;

import com.joy.openggl.util.BufferUtil;

public class Mesh {
	
	 /** Our vertex buffer. */
	 private FloatBuffer mVerticesBuffer = null;

	 /** Our index buffer. */
	 private ShortBuffer mIndicesBuffer = null;

	 /** The number of indices. */
	 private int mNumOfIndices = -1;

	 /** Flat Color */
	 private float[] rgba = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };

	 /** Smooth Colors */
	 private FloatBuffer mColorBuffer = null;

	/** 是否消除背面 */
	protected boolean isCullFaceBack = true;
		
	 /** Translate params. */
	 protected float x = 0;
	 protected float y = 0;
	 protected float z = 0;

	 /** Rotate params. */
	 protected float rx = 0;
	 protected float ry = 0;
	 protected float rz = 0;
	 
	 /** Scale params. */
	 protected float sx = 1.0f;
	 protected float sy = 1.0f;
	 protected float sz = 1.0f;

	 public void draw(GL10 gl) {
		 if(isCullFaceBack) {
			// Counter-clockwise winding.  设置逆时针方法为面的“前面”：
			 gl.glFrontFace(GL10.GL_CCW);  
			 // Enable face culling.  打开 忽略“后面”设置：
			 gl.glEnable(GL10.GL_CULL_FACE);  
			 // What faces to remove with the face culling.  明确指明“忽略“哪个面的代码如下：
			 gl.glCullFace(GL10.GL_BACK); 
		 }
		 
		 // Enabled the vertices buffer for writing and to be used during rendering.
		 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		 // Specifies the location and data format of an array of vertex coordinates to use when rendering.
		 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVerticesBuffer);
		 
		 
		 if (mShouldLoadTexture) {
			 loadGLTexture(gl);
			 mShouldLoadTexture = false;
		 } else if(mShouldBindTexture) {
			 mShouldBindTexture = false;
			 bind(gl);
		 }
		 if (mTextureId != -1 && mTextureBuffer != null) {
			 gl.glEnable(GL10.GL_TEXTURE_2D);
			 // Enable the texture state
			 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	
			 // Point to our buffers
			 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);
			 gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
		 }
		 
		 // Smooth color
		 if (mColorBuffer != null) {
			 // Enable the color array buffer to be used during rendering.
			 gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
			 gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
		 } else {
			// Set float color
			 gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
		 }

		 gl.glTranslatef(x, y, z);
		 gl.glRotatef(rx, 1, 0, 0);
		 gl.glRotatef(ry, 0, 1, 0);
		 gl.glRotatef(rz, 0, 0, 1);
		 gl.glScalef(sx, sy, sz);
	
		 // Point out the where the color buffer is.
		 gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices, GL10.GL_UNSIGNED_SHORT, mIndicesBuffer);
		 
		 if (mColorBuffer != null) {
			 gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
		 }
		 // Disable the vertices buffer.
		 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		 if (mTextureId != -1 && mTextureBuffer != null) {
			 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
			 // Disable the use of textures.
			 gl.glDisable(GL10.GL_TEXTURE_2D);
		 }
		 if(isCullFaceBack) {
			 // Disable face culling.
			 gl.glDisable(GL10.GL_CULL_FACE);
		 }

	 }

	 protected void setVertices(float[] vertices) {
		 mVerticesBuffer = BufferUtil.floatBuffer(vertices);
	 }

	 protected void setIndices(short[] indices) {
		 mIndicesBuffer = BufferUtil.shortBuffer(indices);
		 mNumOfIndices = indices.length;
	 }

	 protected void setColors(float[] colors) {
		 mColorBuffer = BufferUtil.floatBuffer(colors);
	 }
	 
	 protected void setColor(float red, float green, float blue, float alpha) {
		 // Setting the flat color.
		 rgba[0] = red;
		 rgba[1] = green;
		 rgba[2] = blue;
		 rgba[3] = alpha;
	 }
	 
	 private boolean mShouldBindTexture = false;
	 public void setTextureId(int texId) {
		 mTextureId = texId;
		 mShouldBindTexture = true;
	 }
	 private void bind(GL10 gl) {
		// ...and bind it to our array
		  gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
	
		  // Create Nearest Filtered Texture
		  // 需要比较清晰的图像使用 GL10.GL_NEAREST
		  // 而使用GL10.GL_LINEAR则会得到一个较模糊的图像
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
	
		  // Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
		  // 纹理坐标一般用str表示，分别对应xyz，2d纹理用st表示
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);//GL10.GL_CLAMP_TO_EDGE 只靠边线绘制一次。
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,  GL10.GL_CLAMP_TO_EDGE);      // GL10.GL_REPEAT重复Texture。
	
	 }
	 
	// Indicates if we need to load the texture.
	 private boolean mShouldLoadTexture = false;

	// Our texture id.
	 private int mTextureId = -1;

	 // The bitmap we want to load as a texture.
	 private Bitmap mBitmap;

	 /**
	  * Set the bitmap to load into a texture.
	  *
	  * @param bitmap
	  */
	 public void loadBitmap(Bitmap bitmap) {
		 this.mBitmap = bitmap;
		 mShouldLoadTexture = true;
	 }

	 /**
	  * Loads the texture.
	  *
	  * @param gl
	  */
	 private void loadGLTexture(GL10 gl) {
		  // Generate one texture pointer...
		  int[] textures = new int[1];
		  gl.glGenTextures(1, textures, 0);
		  mTextureId = textures[0];
		  
		// Delete a texture.
//		  gl.glDeleteTextures(1, textures, 0);
	
		  // ...and bind it to our array
		  gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
	
		  // Create Nearest Filtered Texture
		  // 需要比较清晰的图像使用 GL10.GL_NEAREST
		  // 而使用GL10.GL_LINEAR则会得到一个较模糊的图像
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
	
		  // Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
		  // 纹理坐标一般用str表示，分别对应xyz，2d纹理用st表示
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);//GL10.GL_CLAMP_TO_EDGE 只靠边线绘制一次。
		  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,  GL10.GL_CLAMP_TO_EDGE);      // GL10.GL_REPEAT重复Texture。
	
		  // Use the Android GLUtils to specify a two-dimensional texture image
		  // from our bitmap
		  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
		  
		  mBitmap.recycle();
	 }

	 
	// Our UV texture buffer.
	 private FloatBuffer mTextureBuffer = null;
	 /**
	  * Set the texture coordinates.
	  *
	  * @param textureCoords
	  */
	 protected void setTextureCoordinates(float[] textureCoords) {
		 mTextureBuffer = BufferUtil.floatBuffer(textureCoords);
	 }

}
